<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FBX模型查看器</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.160.0/examples/js/loaders/FBXLoader.js"></script>
    <script type="importmap">
        {
            "imports": {
                "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
                "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
            }
        }
    </script>
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        dark: '#1E293B',
                        light: '#F8FAFC'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .backdrop-blur-sm {
                backdrop-filter: blur(4px);
            }
            .text-shadow {
                text-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
        }
    </style>
</head>
<body class="bg-gray-900 text-white min-h-screen flex flex-col">
    <!-- 顶部导航栏 -->
    <header class="bg-dark/80 backdrop-blur-sm sticky top-0 z-50 border-b border-gray-800">
        <div class="container mx-auto px-4 py-3 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa fa-cube text-primary text-2xl"></i>
                <h1 class="text-xl font-bold text-white">3D模型查看器</h1>
            </div>
            <div class="flex items-center space-x-4">
                <button id="toggleControlsBtn" class="bg-primary/20 hover:bg-primary/30 text-primary px-3 py-1 rounded-md transition-all duration-300 flex items-center">
                    <i class="fa fa-sliders mr-1"></i>
                    <span>控制面板</span>
                </button>
                <button id="fullscreenBtn" class="bg-primary/20 hover:bg-primary/30 text-primary px-3 py-1 rounded-md transition-all duration-300 flex items-center">
                    <i class="fa fa-expand mr-1"></i>
                    <span>全屏</span>
                </button>
            </div>
        </div>
    </header>

    <!-- 主要内容区 -->
    <main class="flex-grow flex flex-col lg:flex-row">
        <!-- 控制面板 -->
        <aside id="controlsPanel" class="w-full lg:w-80 bg-dark/70 backdrop-blur-sm border-r border-gray-800 p-4 transition-all duration-300 lg:block hidden">
            <div class="space-y-6">
                <div>
                    <h2 class="text-lg font-semibold mb-3 flex items-center">
                        <i class="fa fa-cog text-primary mr-2"></i>模型控制
                    </h2>
                    <div class="space-y-3">
                        <div>
                            <label class="block text-sm text-gray-300 mb-1">旋转速度</label>
                            <input type="range" id="rotationSpeed" min="0" max="0.2" step="0.01" value="0.05" 
                                class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-primary">
                        </div>
                        <div>
                            <label class="block text-sm text-gray-300 mb-1">缩放限制</label>
                            <div class="grid grid-cols-2 gap-2">
                                <input type="number" id="minZoom" placeholder="最小" value="0.1" 
                                    class="bg-gray-800 border border-gray-700 rounded-md px-3 py-1 text-sm w-full">
                                <input type="number" id="maxZoom" placeholder="最大" value="10" 
                                    class="bg-gray-800 border border-gray-700 rounded-md px-3 py-1 text-sm w-full">
                            </div>
                        </div>
                        <div class="pt-2">
                            <button id="resetViewBtn" class="w-full bg-primary hover:bg-primary/80 text-white px-4 py-2 rounded-md transition-all duration-300 flex items-center justify-center">
                                <i class="fa fa-refresh mr-1"></i>重置视图
                            </button>
                        </div>
                    </div>
                </div>

                <div>
                    <h2 class="text-lg font-semibold mb-3 flex items-center">
                        <i class="fa fa-lightbulb-o text-yellow-400 mr-2"></i>光照设置
                    </h2>
                    <div class="space-y-5">
                        <div class="space-y-3">
                            <h3 class="text-base font-medium flex items-center">
                                <i class="fa fa-sun-o text-yellow-400 mr-1"></i>主光源
                            </h3>
                            <div>
                                <label class="block text-sm text-gray-300 mb-1">强度</label>
                                <input type="range" id="directionalIntensity1" min="0" max="2" step="0.1" value="1" 
                                    class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-primary">
                            </div>
                            <div>
                                <label class="block text-sm text-gray-300 mb-1">颜色</label>
                                <input type="color" id="lightColor1" value="#ffffff" 
                                    class="w-full h-8 bg-gray-800 border border-gray-700 rounded-md cursor-pointer">
                            </div>
                            <div class="grid grid-cols-3 gap-2">
                                <div>
                                    <label class="block text-xs text-gray-400 mb-1">X位置</label>
                                    <input type="number" id="lightPosX1" placeholder="X" value="5" 
                                        class="bg-gray-800 border border-gray-700 rounded-md px-3 py-1 text-sm w-full">
                                </div>
                                <div>
                                    <label class="block text-xs text-gray-400 mb-1">Y位置</label>
                                    <input type="number" id="lightPosY1" placeholder="Y" value="5" 
                                        class="bg-gray-800 border border-gray-700 rounded-md px-3 py-1 text-sm w-full">
                                </div>
                                <div>
                                    <label class="block text-xs text-gray-400 mb-1">Z位置</label>
                                    <input type="number" id="lightPosZ1" placeholder="Z" value="5" 
                                        class="bg-gray-800 border border-gray-700 rounded-md px-3 py-1 text-sm w-full">
                                </div>
                            </div>
                        </div>

                        <div class="space-y-3">
                            <h3 class="text-base font-medium flex items-center">
                                <i class="fa fa-moon-o text-blue-400 mr-1"></i>辅助光源
                            </h3>
                            <div>
                                <label class="block text-sm text-gray-300 mb-1">强度</label>
                                <input type="range" id="directionalIntensity2" min="0" max="2" step="0.1" value="0.5" 
                                    class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-primary">
                            </div>
                            <div>
                                <label class="block text-sm text-gray-300 mb-1">颜色</label>
                                <input type="color" id="lightColor2" value="#80a0ff" 
                                    class="bg-gray-800 border border-gray-700 rounded-md cursor-pointer">
                            </div>
                            <div class="grid grid-cols-3 gap-2">
                                <div>
                                    <label class="block text-xs text-gray-400 mb-1">X位置</label>
                                    <input type="number" id="lightPosX2" placeholder="X" value="-5" 
                                        class="bg-gray-800 border border-gray-700 rounded-md px-3 py-1 text-sm w-full">
                                </div>
                                <div>
                                    <label class="block text-xs text-gray-400 mb-1">Y位置</label>
                                    <input type="number" id="lightPosY2" placeholder="Y" value="3" 
                                        class="bg-gray-800 border border-gray-700 rounded-md px-3 py-1 text-sm w-full">
                                </div>
                                <div>
                                    <label class="block text-xs text-gray-400 mb-1">Z位置</label>
                                    <input type="number" id="lightPosZ2" placeholder="Z" value="-3" 
                                        class="bg-gray-800 border border-gray-700 rounded-md px-3 py-1 text-sm w-full">
                                </div>
                            </div>
                        </div>

                        <div>
                            <h3 class="text-base font-medium flex items-center">
                                <i class="fa fa-cloud text-gray-400 mr-1"></i>环境光
                            </h3>
                            <div>
                                <label class="block text-sm text-gray-300 mb-1">强度</label>
                                <input type="range" id="ambientIntensity" min="0" max="2" step="0.1" value="0.2" 
                                    class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-primary">
                            </div>
                        </div>
                    </div>
                </div>

                <div>
                    <h2 class="text-lg font-semibold mb-3 flex items-center">
                        <i class="fa fa-info-circle text-blue-400 mr-2"></i>模型信息
                    </h2>
                    <div class="space-y-2 bg-gray-800/50 p-3 rounded-md border border-gray-700">
                        <p><span class="text-gray-400">状态:</span> <span id="modelStatus" class="text-yellow-400">加载中...</span></p>
                        <p><span class="text-gray-400">文件大小:</span> <span id="fileSize">-</span></p>
                        <p><span class="text-gray-400">加载时间:</span> <span id="loadTime">-</span></p>
                        <p><span class="text-gray-400">面数:</span> <span id="faceCount">-</span></p>
                    </div>
                </div>
            </div>
        </aside>

        <!-- 3D视图区域 -->
        <section class="flex-grow relative overflow-hidden" id="modelContainer">
            <div class="absolute inset-0 flex items-center justify-center bg-gray-900/90 z-10" id="loadingOverlay">
                <div class="text-center">
                    <div class="inline-block animate-spin rounded-full h-12 w-12 border-4 border-primary border-t-transparent mb-4"></div>
                    <p class="text-xl font-medium">正在加载模型...</p>
                    <p class="text-gray-400 mt-2">请稍候，这可能需要一些时间...</p>
                </div>
            </div>
            <canvas id="renderCanvas" class="w-full h-full"></canvas>
            <div class="absolute bottom-4 left-4 bg-dark/60 backdrop-blur-sm p-3 rounded-lg border border-gray-700 z-10">
                <p class="text-sm text-gray-300">操作提示:</p>
                <div class="grid grid-cols-2 gap-x-4 gap-y-1 mt-1 text-xs text-gray-400">
                    <div><i class="fa fa-mouse-pointer mr-1"></i> 左键: 旋转</div>
                    <div><i class="fa fa-arrows-alt mr-1"></i> 中键: 平移</div>
                    <div><i class="fa fa-search mr-1"></i> 滚轮: 缩放</div>
                    <div><i class="fa fa-hand-paper-o mr-1"></i> 右键: 平移</div>
                </div>
            </div>
        </section>
    </main>

    <!-- 页脚 -->
    <footer class="bg-dark/80 backdrop-blur-sm border-t border-gray-800 py-3">
        <div class="container mx-auto px-4 text-center text-sm text-gray-400">
            <p>© 2025 3D模型查看器 | 使用 Three.js 构建</p>
        </div>
    </footer>

    <script type="module">
        // 从模块导入必要的类
        import * as THREE from 'three';
        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
        import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';
        
        // 初始化变量
        let scene, camera, renderer, controls, fbxLoader, model;
        let ambientLight, directionalLight1, directionalLight2; // 添加第二个方向光
        let clock = new THREE.Clock();
        let isModelLoaded = false;
        let modelLoadStartTime, modelLoadEndTime;
        
        // 模型URL
        const modelUrl = 'https://duxinggj-1251133427.cos.ap-guangzhou.myqcloud.com/case/20250228/111.fbx';
        
        // 初始化Three.js场景
        function init() {
            try {
                // 创建场景
                scene = new THREE.Scene();
                scene.background = new THREE.Color(0x121212);
                
                // 创建相机
                camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 2000);
                camera.position.z = 5;
                
                // 创建渲染器
                renderer = new THREE.WebGLRenderer({
                    canvas: document.getElementById('renderCanvas'),
                    antialias: true,
                    alpha: false
                });
                renderer.setPixelRatio(window.devicePixelRatio);
                renderer.setSize(window.innerWidth, window.innerHeight);
                renderer.outputEncoding = THREE.sRGBEncoding;
                
                // 添加环境光
                ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
                scene.add(ambientLight);
                
                // 添加第一个方向光（主光源）
                directionalLight1 = new THREE.DirectionalLight(0xffffff, 1);
                directionalLight1.position.set(5, 5, 5);
                scene.add(directionalLight1);
                
                // 添加第二个方向光（辅助光源）
                directionalLight2 = new THREE.DirectionalLight(0x80a0ff, 0.5);
                directionalLight2.position.set(-5, 3, -3);
                scene.add(directionalLight2);
                
                // 添加辅助网格
                const gridHelper = new THREE.GridHelper(10, 10, 0x333333, 0x111111);
                scene.add(gridHelper);
                
                // 添加坐标轴辅助
                const axesHelper = new THREE.AxesHelper(5);
                scene.add(axesHelper);
                
                // 添加光照辅助
                const directionalLightHelper1 = new THREE.DirectionalLightHelper(directionalLight1, 1);
                scene.add(directionalLightHelper1);
                
                const directionalLightHelper2 = new THREE.DirectionalLightHelper(directionalLight2, 1);
                scene.add(directionalLightHelper2);
                
                // 添加轨道控制器
                controls = new OrbitControls(camera, renderer.domElement);
                controls.enableDamping = true;
                controls.dampingFactor = 0.05;
                controls.rotateSpeed = 0.5;
                
                // 加载FBX模型
                loadFBXModel();
                
                // 添加窗口大小调整事件
                window.addEventListener('resize', onWindowResize);
                
                // 添加控制面板切换事件
                document.getElementById('toggleControlsBtn').addEventListener('click', toggleControlsPanel);
                
                // 添加全屏切换事件
                document.getElementById('fullscreenBtn').addEventListener('click', toggleFullscreen);
                
                // 添加重置视图事件
                document.getElementById('resetViewBtn').addEventListener('click', resetView);
                
                // 添加控制器事件 - 主光源
                document.getElementById('directionalIntensity1').addEventListener('input', updateDirectionalLight1);
                document.getElementById('lightColor1').addEventListener('input', updateLightColor1);
                document.getElementById('lightPosX1').addEventListener('change', updateDirectionalLight1);
                document.getElementById('lightPosY1').addEventListener('change', updateDirectionalLight1);
                document.getElementById('lightPosZ1').addEventListener('change', updateDirectionalLight1);
                
                // 添加控制器事件 - 辅助光源
                document.getElementById('directionalIntensity2').addEventListener('input', updateDirectionalLight2);
                document.getElementById('lightColor2').addEventListener('input', updateLightColor2);
                document.getElementById('lightPosX2').addEventListener('change', updateDirectionalLight2);
                document.getElementById('lightPosY2').addEventListener('change', updateDirectionalLight2);
                document.getElementById('lightPosZ2').addEventListener('change', updateDirectionalLight2);
                
                // 添加控制器事件 - 环境光
                document.getElementById('ambientIntensity').addEventListener('input', updateAmbientLight);
                
                // 添加控制器事件 - 模型控制
                document.getElementById('rotationSpeed').addEventListener('input', updateRotationSpeed);
                document.getElementById('minZoom').addEventListener('change', updateZoomLimits);
                document.getElementById('maxZoom').addEventListener('change', updateZoomLimits);
                
                // 开始渲染循环
                animate();
            } catch (error) {
                console.error('初始化Three.js场景时出错:', error);
                document.getElementById('loadingOverlay').style.display = 'none';
                document.getElementById('modelStatus').textContent = '初始化失败';
                document.getElementById('modelStatus').className = 'text-red-500';
                alert('初始化Three.js场景失败: ' + error.message);
            }
        }
        
        // 加载FBX模型
        function loadFBXModel() {
            modelLoadStartTime = performance.now();
            
            fbxLoader = new FBXLoader();
            
            // 显示加载覆盖层
            document.getElementById('loadingOverlay').style.display = 'flex';
            
            fbxLoader.load(
                modelUrl,
                // 加载成功
                function (object) {
                    modelLoadEndTime = performance.now();
                    const loadTime = ((modelLoadEndTime - modelLoadStartTime) / 1000).toFixed(2);
                    
                    model = object;
                    scene.add(model);
                    
                    // 计算模型的包围盒，用于自动调整相机位置
                    const box = new THREE.Box3().setFromObject(model);
                    const center = box.getCenter(new THREE.Vector3());
                    const size = box.getSize(new THREE.Vector3());
                    
                    // 居中模型
                    model.position.sub(center);
                    
                    // 计算适合的相机距离
                    const maxDim = Math.max(size.x, size.y, size.z);
                    const fov = camera.fov * (Math.PI / 180);
                    let cameraZ = Math.abs(maxDim / 2 / Math.tan(fov / 2));
                    cameraZ *= 1.5; // 添加一些边距
                    
                    // 设置相机位置和目标
                    camera.position.z = cameraZ;
                    controls.target.set(0, 0, 0);
                    
                    // 设置缩放限制
                    controls.minDistance = maxDim * 0.1;
                    controls.maxDistance = maxDim * 10;
                    
                    document.getElementById('minZoom').value = controls.minDistance;
                    document.getElementById('maxZoom').value = controls.maxDistance;
                    
                    // 更新模型信息
                    updateModelInfo(model, loadTime);
                    
                    isModelLoaded = true;
                    
                    // 隐藏加载覆盖层
                    document.getElementById('loadingOverlay').style.display = 'none';
                    
                    // 显示成功消息
                    document.getElementById('modelStatus').textContent = '加载成功';
                    document.getElementById('modelStatus').className = 'text-green-400';
                },
                // 加载进度
                function (xhr) {
                    const percentComplete = (xhr.loaded / xhr.total) * 100;
                    // 可以在这里更新进度条
                },
                // 加载错误
                function (error) {
                    console.error('加载模型时出错:', error);
                    
                    // 隐藏加载覆盖层
                    document.getElementById('loadingOverlay').style.display = 'none';
                    
                    // 显示错误消息
                    document.getElementById('modelStatus').textContent = '加载失败';
                    document.getElementById('modelStatus').className = 'text-red-500';
                    
                    // 显示错误详情
                    alert('加载模型失败: ' + error.message);
                }
            );
        }
        
        // 更新模型信息
        function updateModelInfo(model, loadTime) {
            // 计算面数
            let faceCount = 0;
            model.traverse(function(child) {
                if (child.isMesh) {
                    const geometry = child.geometry;
                    if (geometry.index !== null) {
                        faceCount += geometry.index.count / 3;
                    } else {
                        faceCount += geometry.attributes.position.count / 3;
                    }
                }
            });
            
            // 更新DOM
            document.getElementById('loadTime').textContent = loadTime + '秒';
            document.getElementById('faceCount').textContent = faceCount.toLocaleString();
            
            // 获取文件大小 (通过HEAD请求)
            fetch(modelUrl, { method: 'HEAD' })
                .then(response => {
                    const sizeInBytes = response.headers.get('Content-Length');
                    if (sizeInBytes) {
                        const sizeInKB = (sizeInBytes / 1024).toFixed(2);
                        const sizeInMB = (sizeInBytes / (1024 * 1024)).toFixed(2);
                        
                        const sizeText = sizeInMB > 1 ? sizeInMB + ' MB' : sizeInKB + ' KB';
                        document.getElementById('fileSize').textContent = sizeText;
                    }
                })
                .catch(error => {
                    console.error('获取文件大小时出错:', error);
                    document.getElementById('fileSize').textContent = '未知';
                });
        }
        
        // 窗口大小调整处理
        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
        
        // 切换控制面板显示/隐藏
        function toggleControlsPanel() {
            const panel = document.getElementById('controlsPanel');
            panel.classList.toggle('hidden');
            panel.classList.toggle('lg:block');
        }
        
        // 切换全屏模式
        function toggleFullscreen() {
            const container = document.getElementById('modelContainer');
            
            if (!document.fullscreenElement) {
                if (container.requestFullscreen) {
                    container.requestFullscreen();
                } else if (container.webkitRequestFullscreen) { /* Safari */
                    container.webkitRequestFullscreen();
                } else if (container.msRequestFullscreen) { /* IE11 */
                    container.msRequestFullscreen();
                }
            } else {
                if (document.exitFullscreen) {
                    document.exitFullscreen();
                } else if (document.webkitExitFullscreen) { /* Safari */
                    document.webkitExitFullscreen();
                } else if (document.msExitFullscreen) { /* IE11 */
                    document.msExitFullscreen();
                }
            }
        }
        
        // 重置视图
        function resetView() {
            if (model && controls) {
                // 计算模型的包围盒
                const box = new THREE.Box3().setFromObject(model);
                const size = box.getSize(new THREE.Vector3());
                
                // 计算适合的相机距离
                const maxDim = Math.max(size.x, size.y, size.z);
                const fov = camera.fov * (Math.PI / 180);
                let cameraZ = Math.abs(maxDim / 2 / Math.tan(fov / 2));
                cameraZ *= 1.5; // 添加一些边距
                
                // 设置相机位置和目标
                camera.position.set(0, 0, cameraZ);
                controls.target.set(0, 0, 0);
                
                // 重置控制器
                controls.reset();
                
                // 重置灯光
                directionalLight1.position.set(5, 5, 5);
                directionalLight2.position.set(-5, 3, -3);
                document.getElementById('lightPosX1').value = 5;
                document.getElementById('lightPosY1').value = 5;
                document.getElementById('lightPosZ1').value = 5;
                document.getElementById('lightPosX2').value = -5;
                document.getElementById('lightPosY2').value = 3;
                document.getElementById('lightPosZ2').value = -3;
            }
        }
        
        // 更新旋转速度
        function updateRotationSpeed() {
            const speed = parseFloat(this.value);
            controls.rotateSpeed = speed;
        }
        
        // 更新环境光
        function updateAmbientLight() {
            const intensity = parseFloat(this.value);
            ambientLight.intensity = intensity;
        }
        
        // 更新第一个方向光
        function updateDirectionalLight1() {
            const intensity = parseFloat(document.getElementById('directionalIntensity1').value);
            const x = parseFloat(document.getElementById('lightPosX1').value);
            const y = parseFloat(document.getElementById('lightPosY1').value);
            const z = parseFloat(document.getElementById('lightPosZ1').value);
            
            directionalLight1.intensity = intensity;
            directionalLight1.position.set(x, y, z);
        }
        
        // 更新第一个方向光颜色
        function updateLightColor1() {
            const color = this.value;
            directionalLight1.color.set(color);
        }
        
        // 更新第二个方向光
        function updateDirectionalLight2() {
            const intensity = parseFloat(document.getElementById('directionalIntensity2').value);
            const x = parseFloat(document.getElementById('lightPosX2').value);
            const y = parseFloat(document.getElementById('lightPosY2').value);
            const z = parseFloat(document.getElementById('lightPosZ2').value);
            
            directionalLight2.intensity = intensity;
            directionalLight2.position.set(x, y, z);
        }
        
        // 更新第二个方向光颜色
        function updateLightColor2() {
            const color = this.value;
            directionalLight2.color.set(color);
        }
        
        // 更新缩放限制
        function updateZoomLimits() {
            const minZoom = parseFloat(document.getElementById('minZoom').value);
            const maxZoom = parseFloat(document.getElementById('maxZoom').value);
            
            if (!isNaN(minZoom) && !isNaN(maxZoom) && minZoom < maxZoom) {
                controls.minDistance = minZoom;
                controls.maxDistance = maxZoom;
            }
        }
        
        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            
            if (model && controls) {
                controls.update();
            }
            
            renderer.render(scene, camera);
        }
        
        // 当DOM加载完成后初始化
        document.addEventListener('DOMContentLoaded', init);
    </script>
</body>
</html>